package com.i72.penetrate.rpc;

import com.alibaba.fastjson.JSON;
import com.i72.basic.consts.Consts;
import com.i72.basic.context.GlobalContext;
import com.i72.basic.exception.BusinessException;
import com.i72.basic.tools.BeanHelper;
import com.i72.governance.service.bean.ServiceInfo;
import com.i72.governance.service.bean.ServiceNode;
import com.i72.governance.service.helper.ServiceHelper;
import com.i72.penetrate.blance.RPCBlance;
import com.i72.penetrate.tools.HttpRequestHelper;
import com.i72.penetrate.validate.RPCValidate;
import com.i72.penetrate.web.ResponseFormat;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpEntity;
import org.springframework.util.StringUtils;
import org.springframework.web.client.RestTemplate;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.regex.Pattern;

@Slf4j
public abstract class RPCBase {


    public String className = "";

    public String classFullName = "";

    private Pattern SERVICE = Pattern.compile("service",Pattern.CASE_INSENSITIVE);

    @Autowired
    private RestTemplate restTemplate;

    @Autowired
    private ServiceHelper serviceHelper;

    @Autowired
    private RPCBlance rpcBlance;

    @Autowired
    private RPCValidate rpcValidate;

    @Autowired
    private HttpRequestHelper httpRequestHelper;



    private String controllerName = "";

    private Map<String,String> servicePackageMapping = new HashMap<>();

    private Map<String,Method> methodMap = new HashMap<>();

    private String analyzeService(String classFullName){

        List<ServiceInfo> serviceInfoList = serviceHelper.getAllServiceInfo();
        if(serviceInfoList!=null && serviceInfoList.size()>0){

            for(ServiceInfo serviceInfo:serviceInfoList){
                if(serviceInfo.getServiceNodes()!=null && serviceInfo.getServiceNodes().size()>0){

                    ServiceNode serviceNode = serviceInfo.getServiceNodes().get(0);

                    if(serviceNode.getMetadata().containsKey(Consts.SERVICE_PACKAGE)){
                        String packageName = serviceNode.getMetadata().get(Consts.SERVICE_PACKAGE);
                        if(!StringUtils.isEmpty(packageName)){

                            if(classFullName.contains(packageName))
                            servicePackageMapping.put(classFullName,serviceInfo.getServiceName());

                            return serviceInfo.getServiceName();
                        }
                    }

                }
            }

        }
        return null;

    }

    private String analyzeController(String classNameInfo){

        if(StringUtils.isEmpty(this.controllerName)) {
            this.controllerName = SERVICE.matcher(classNameInfo).replaceAll("");
        }
        return this.controllerName;
    }

    private String getServiceNode(String serviceName){

        ServiceInfo serviceInfo = serviceHelper.getServiceInfo(serviceName);

        if(serviceInfo!=null && serviceInfo.getServiceNodes()!=null && serviceInfo.getServiceNodes().size()>0){
            //负载均衡算法，选择一个。
            ServiceNode serviceNode = rpcBlance.voteNode(serviceInfo.getServiceNodes());

            if(serviceNode!=null){
                return serviceNode.getIp()+":"+serviceNode.getPort().toString();
            }
        }

        return null;
    }

    private String gerUrl(String serviceName,String classNameInfo,String method){
        String node = getServiceNode(serviceName);

        if(StringUtils.isEmpty(node)) {
            return null;
        }

        String controller = analyzeController(classNameInfo);

        String url = GlobalContext.getProtocol()+"://"+node+"/"+controller+"/"+method;

        return url;
    }

    public <T> T request(String method,Object... param){


        //参数检查

        if(param!=null && param.length==1) {
            boolean result = rpcValidate.validate(param[0]);

            if (!result) {
                log.error("RPC调用错误，错误信息：" + httpRequestHelper.getValidateMessage());
                return null;
            }
        }


        //StackTraceElement[] stackTraceElements = Thread.currentThread().getStackTrace();
        String serviceName = "";
        if(!servicePackageMapping.containsKey(this.classFullName)){
            serviceName = analyzeService(this.classFullName);
            if(StringUtils.isEmpty(serviceName)){
                log.error("package:"+this.classFullName+"无法解析到正确的服务");
                return null;
            }
        }

        serviceName = servicePackageMapping.get(this.classFullName);

        String url = gerUrl(serviceName,this.className,method);



        Object p = httpRequestHelper.getHttpParam(methodMap.get(method),param);
        //String v = restTemplate.postForObject("",null,String.class);



        HttpEntity<String> entity = restTemplate.postForEntity(url,p,String.class);

        if(!StringUtils.isEmpty(entity.getBody())){
            ResponseFormat format = JSON.parseObject(entity.getBody(),ResponseFormat.class);
            if(format.getData()==null){
                return null;
            }
            return (T)format.getData();
        }
        return null;

    }

    public String request(){
        StackTraceElement[] stackTraceElements = Thread.currentThread().getStackTrace();
        return null;
    }

    /**
     * 初始化参数
     */
    public void initParams(){

        //获取声明接口上的方法对象。
        Class [] interfaceList = this.getClass().getInterfaces();

        if(interfaceList!=null && interfaceList.length>0){
            for(Class c:interfaceList){
                List<Method> ms = BeanHelper.getMethod(c);

                if(ms!=null && ms.size()>0){
                    for(Method m:ms){
                        methodMap.put(m.getName(),m);
                    }
                }
            }
        }
    }
}
